//package com.flyway.execise.flyway_db;
//
///*
// * Copyright (c) 2008, 2010, Kilimall and/or its affiliates. All rights reserved.
// *
// * Redistribution and use in source and binary forms, with or without
// * modification, are permitted provided that the following conditions
// * are met:
// *
// *   - Redistributions of source code must retain the above copyright
// *     notice, this list of conditions and the following disclaimer.
// *
// *   - Redistributions in binary form must reproduce the above copyright
// *     notice, this list of conditions and the following disclaimer in the
// *     documentation and/or other materials provided with the distribution.
// *
// *   - Neither the name of Oracle nor the names of its
// *     contributors may be used to endorse or promote products derived
// *     from this software without specific prior written permission.
// *
// */
//
//
//import lombok.extern.slf4j.Slf4j;
//import org.springframework.beans.BeanUtils;
//import org.springframework.beans.factory.NoSuchBeanDefinitionException;
//import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
//import org.springframework.beans.factory.config.BeanDefinition;
//import org.springframework.beans.factory.support.*;
//import org.springframework.boot.env.OriginTrackedMapPropertySource;
//import org.springframework.context.ApplicationContext;
//import org.springframework.context.annotation.ScannedGenericBeanDefinition;
//import org.springframework.core.env.Environment;
//import org.springframework.core.env.MutablePropertySources;
//import org.springframework.core.env.PropertySource;
//import org.springframework.util.ReflectionUtils;
//import org.springframework.web.context.support.StandardServletEnvironment;
//import org.springframework.web.method.support.InvocableHandlerMethod;
//import org.springframework.web.servlet.DispatcherServlet;
//import org.springframework.web.servlet.handler.AbstractHandlerMethodMapping;
//import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
//import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
//import sun.misc.Launcher;
//
//import java.io.*;
//import java.lang.reflect.Method;
//import java.net.URI;
//import java.net.URL;
//import java.net.URLClassLoader;
//import java.nio.ByteBuffer;
//import java.nio.channels.Channels;
//import java.nio.channels.FileChannel;
//import java.nio.channels.WritableByteChannel;
//import java.nio.file.*;
//import java.nio.file.attribute.BasicFileAttributes;
//import java.util.*;
//
//import static java.lang.Class.*;
//import static java.nio.file.LinkOption.NOFOLLOW_LINKS;
//import static java.nio.file.StandardWatchEventKinds.*;
//
//
///**
// * Example to watch a directory (or tree) for changes to files.
// * @date 19-7-15
// * @auther jackliang
// * @description TODO
// */
//@Slf4j
//public class WatcherDir {
//
//    private final WatchService watcher;
//    private final Map<WatchKey,Path> keys;
//    private final boolean recursive;
//    private boolean trace;
//    private Environment environment;
//    private ApplicationContext applicationContext;
//    private List<String>  pPatternContainer = Arrays.asList(".properties",".class");
//
//    @SuppressWarnings("unchecked")
//    static <T> WatchEvent<T> cast(WatchEvent<?> event) {
//        return (WatchEvent<T>)event;
//    }
//
//    /**
//     * Register the given directory with the WatchService
//     */
//    private void register(Path dir) throws IOException {
//        WatchKey key = dir.register(watcher, ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY);
//        if (trace) {
//            Path prev = keys.get(key);
//            if (prev == null) {
//                System.out.format("register: %s\n", dir);
//            } else {
//                if (!dir.equals(prev)) {
//                    System.out.format("update: %s -> %s\n", prev, dir);
//                }
//            }
//        }
//        keys.put(key, dir);
//    }
//
//    /**
//     * Register the given directory, and all its sub-directories, with the
//     * WatchService.
//     */
//    private void registerAll(final Path start) throws IOException {
//        // register directory and sub-directories
//        Files.walkFileTree(start, new SimpleFileVisitor<Path>() {
//            @Override
//            public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs)
//                    throws IOException
//            {
//                register(dir);
//                return FileVisitResult.CONTINUE;
//            }
//        });
//    }
//
//    /**
//     * Creates a WatchService and registers the given directory
//     */
//    WatcherDir(Path dir, boolean recursive, Environment environment, ApplicationContext applicationContext) throws Exception {
//        this.watcher = FileSystems.getDefault().newWatchService();
//        this.keys = new HashMap<>();
//        this.recursive = recursive;
//        this.environment=environment;
//        this.applicationContext=applicationContext;
//
//        if (recursive) {
//            System.out.format("Scanning %s ...\n", dir);
//            registerAll(dir);
//            System.out.println("Done.");
//        } else {
//            register(dir);
//        }
//
//        // enable trace after initial registration
//        this.trace = true;
//        this.processEvents();
//    }
//
//
//    private boolean catchDeleteEvent(WatchKey key) throws Exception {
//        Iterator<WatchEvent<?>> iter = key.pollEvents().iterator();
//
//        if (iter.hasNext() && iter.next().kind() == ENTRY_DELETE) {
//            log.info("Delete entry signal was be catched for {}",ENTRY_DELETE.name());
//            this.compileCorrespondingResource();
//            return true;
//        }
//
//        //this.compileCorrespondingResource();
//        return false;
//    }
//
//
//    /**
//     * Process all events for keys queued to the watcher
//     */
//    void processEvents() throws Exception {
//        for (;;) {
//
//            // wait for key to be signalled
//            WatchKey key;
//            try {
//                key = watcher.take();
//                System.err.println("One event was be catched ");
//            } catch (InterruptedException x) {
//                return;
//            }
//
//            this.catchDeleteEvent(key);
//
//            //key.
//            Path dir = keys.get(key);
//            if (dir == null) {
//                System.err.println("WatchKey not recognized!!");
//                continue;
//            }
//            System.out.println(dir.toString());
//
////            //StartUp to  heat deploy logically ~
//            this.compileCorrespondingResource();
//
//
//            for (WatchEvent<?> event: key.pollEvents()) {
//                WatchEvent.Kind kind = event.kind();
//
//                // TBD - provide example of how OVERFLOW event is handled
//                if (kind == OVERFLOW) {
//                    continue;
//                }
//                // Context for directory entry event is the file name of entry
//                WatchEvent<Path> ev = cast(event);
//                Path name = ev.context();
//                Path path = dir.resolve(name);
//
//                Iterator<String> iterator = pPatternContainer.iterator();
//
//                boolean flag =  false;
//
//                while (iterator.hasNext()){
//                    if (path.toString().endsWith(iterator.next())){
//                        flag = true;
//                        break;
//                    }
//                }
//
//                if (!flag){
//                    continue;
//                }
//
//                this.PropertyReloadThroughPath(path);
//
//                ClassLoader loader = Thread.currentThread().getContextClassLoader();
//                URI uri = path.normalize().toUri();
//                //MyClassLoader loader1= new MyClassLoader();
//                this.compileCorrespondingResource();
//
//                 //cls= forName("com.flyway.execise.flyway_db.Controller",true,loader);
//                 File file =  new File("/home/jackliang/works/flyway_db/target/classes/com/flyway/execise/flyway_db/Controller.class");
//                byte [] bytes = getClassFileBytes(file);
//                HotClassLoader hotClassLoader = new HotClassLoader();
//                Class cls= hotClassLoader.findClass("com.flyway.execise.flyway_db.Controller",bytes);
//                 AutowireCapableBeanFactory factory = applicationContext.getAutowireCapableBeanFactory();
//                 DefaultListableBeanFactory defaultListableBeanFactory = (DefaultListableBeanFactory)factory;
//                BeanDefinition beanDefinition= defaultListableBeanFactory.getBeanDefinition("controller");
//
//                // resolveBeanClass
//                Class<?> cls1 = ((AbstractBeanDefinition)beanDefinition).resolveBeanClass(hotClassLoader);
//                assert cls1.isAssignableFrom(cls);
//
//                ((ScannedGenericBeanDefinition)beanDefinition).setBeanClass(cls);
//                defaultListableBeanFactory.setAllowBeanDefinitionOverriding(true);
//                DispatcherServlet dispatcherServlet = defaultListableBeanFactory.getBean(DispatcherServlet.class);
//                RequestMappingHandlerMapping requestMappingHandlerMapping = defaultListableBeanFactory.getBean(RequestMappingHandlerMapping.class);
//                RequestMappingInfo.Builder builder = RequestMappingInfo.paths("test1");
//                RequestMappingInfo requestMappingInfo  = builder.build();
//                requestMappingHandlerMapping.unregisterMapping(requestMappingInfo);
//
//                Method method = ReflectionUtils.findMethod(cls,"test1");
//
//                requestMappingHandlerMapping.registerMapping(requestMappingInfo,"controller",method);
//
//
//                //requestMappingHandlerMapping.registerMapping();
//
//
//
//                defaultListableBeanFactory.removeBeanDefinition("controller");
//                defaultListableBeanFactory.registerBeanDefinition("controller",beanDefinition);
//
//                //requestMappingHandlerMapping
//                BeanDefinition beanDefinition2= defaultListableBeanFactory.getBeanDefinition("controller");
//                Method method1 = cls.getMethod("test1");
//                Object obj1 = cls.newInstance();
//
//
//                Object classs  =  defaultListableBeanFactory.getBean("controller");
////                Method method1 = classs.getClass().getMethod("test1",new Class[]{});
//                ReflectionUtils.invokeMethod(method1,obj1);
//
//
//                //                 if directory is created, and watching recursively, then
////                 register it and its sub-directories
//                if (recursive && (kind == ENTRY_CREATE)) {
//                    try {
//                        if (Files.isDirectory(path, NOFOLLOW_LINKS)) {
//                            registerAll(path);
//                        }
//                    } catch (IOException x) {
//                        // ignore to keep sample readbale
//                    }
//                }
//            }
//
//            // reset key and remove from set if directory no longer accessible
//            boolean valid = key.reset();
//            if (!valid) {
//                keys.remove(key);
//
//                // all directories are inaccessible
//                if (keys.isEmpty()) {
//                    break;
//                }
//            }
//        }
//    }
//
//
//
//    private void PropertyReloadThroughPath(Path path) throws IOException {
//        assert environment instanceof  StandardServletEnvironment;
//        StandardServletEnvironment standardServletEnvironment = (StandardServletEnvironment) environment;
//        MutablePropertySources mutablePropertySources = standardServletEnvironment.getPropertySources();
//        //mutablePropertySources.
//        PropertySource propertySource = mutablePropertySources.get("applicationConfig: [classpath:/application.properties]");
//        Map<String, Object> maps = ((OriginTrackedMapPropertySource) propertySource).getSource();
//
//        if (!path.toString().endsWith("properties")){return ;}
//
//        InputStream uls = path.
//                toUri().
//                toURL().
//                openStream();
//
//        Properties p = new Properties();
//        p.load(uls);
//        maps.putAll((Map) p);
//    }
//
//
//    private void reloadWithHeatOfUpdatedClass(Path path) {
//        ClassLoader loader = Thread.currentThread().getContextClassLoader();
//        URI uri = path.normalize().toUri();
//    }
//
//
//    /**
//     * 把CLASS文件转成BYTE
//     *
//     * @throws Exception
//     */
//    private byte[] getClassFileBytes(File file) throws Exception {
//        //采用NIO读取
//        FileInputStream fis = new FileInputStream(file);
//        FileChannel fileC = fis.getChannel();
//        ByteArrayOutputStream baos = new ByteArrayOutputStream();
//        WritableByteChannel outC = Channels.newChannel(baos);
//        ByteBuffer buffer = ByteBuffer.allocateDirect(1024);
//        while (true) {
//            int i = fileC.read(buffer);
//            if (i == 0 || i == -1) {
//                break;
//            }
//            buffer.flip();
//            outC.write(buffer);
//            buffer.clear();
//        }
//        fis.close();
//        return baos.toByteArray();
//    }
//
//    private void compileCorrespondingResource() throws Exception {
//        Process process1 = Runtime.getRuntime().exec("mvn clean  compile ");
//        int status = process1.waitFor();
//
//        if (status != 0) {
//            System.out.println("Failed to call shell's command\t");
//        }
//
//        BufferedReader br1 = new BufferedReader(new InputStreamReader(process1.getInputStream()));
//        while (br1.readLine() != null) {
//            System.out.println(br1.readLine());
//        }
//    }
//
//}
//
//
//
//class HotClassLoader extends ClassLoader {
//
//    public HotClassLoader() {
//        super(ClassLoader.getSystemClassLoader());
//    }
//
//    private File objFile;
//
//    public File getObjFile() {
//        return objFile;
//    }
//
//    public void setObjFile(File objFile) {
//        this.objFile = objFile;
//    }
//
//    protected Class<?> findClass(String name,byte [] bytes) throws ClassNotFoundException {
//        //这个classLoader的主要方法
//        System.out.println("findClassfindClassfindClassfindClass");
//        Class clazz = null;
//        try {
//            clazz = defineClass(name, bytes, 0, bytes.length);
//            if (null == clazz) {
//
//            }
//        } catch (Exception e) {
//            e.printStackTrace();
//        }
//        return clazz;
//
//    }
//
//    /**
//     * 把CLASS文件转成BYTE
//     *
//     * @throws Exception
//     */
//    private byte[] getClassFileBytes(File file) throws Exception {
//        //采用NIO读取
//        FileInputStream fis = new FileInputStream(file);
//        FileChannel fileC = fis.getChannel();
//        ByteArrayOutputStream baos = new ByteArrayOutputStream();
//        WritableByteChannel outC = Channels.newChannel(baos);
//        ByteBuffer buffer = ByteBuffer.allocateDirect(1024);
//        while (true) {
//            int i = fileC.read(buffer);
//            if (i == 0 || i == -1) {
//                break;
//            }
//            buffer.flip();
//            outC.write(buffer);
//            buffer.clear();
//        }
//        fis.close();
//        return baos.toByteArray();
//    }
//
//}

